Dockerプライベートリポジトリ(Docker Registry)構築レシピ
ども、大瀧です。
AWS Elastic BeanstalkのDocker対応、Amazon ECSの正式リリースからちょっと経ちますが、皆さん使っていますか?業務用途だとDockerイメージを共有するためのプライベートなDockerリポジトリが欲しくなるところですが、マネージドなDockerリポジトリサービスは現在AWSでは提供されていないため、自前で用意することもあると思います。今回は、自前でDockerリポジトリを構築するときのTipsをご紹介します。
Docker Registryを使う
Dockerリポジトリは、Docker RegistryというDocker公式のリポジトリ実装が公開されているため、特別な事情が無ければこちらを利用するのが良いでしょう。大規模なケースであれば、まだリリース前ですがDocker Hub Enterpriseという選択肢も頭の片隅に置いておいて良いかもしれません。
v1にするかv2にするか
Docker Registryには現在、v1系とv2系という2つのバージョンがあります。GitHubの異なるリポジトリで開発されており、v1系の方が古くREADMEではv2系が推奨とされています。v2系ではDocker 1.6とともにイメージ管理に関する機能強化が図られているため、特別な要件が無ければv2系がお奨めです。ただ、若いプロダクトで情報が少なかったり、ちまちまバグがあったりという状況なので一応、v1系の設定方法も併記します。v1とv2でバックエンドストレージの互換性は無いので、一つのバケットで両バージョンのデータを格納する場合は、階層が重複しないようプレフィックスを調節しましょう。
なお、v1/v2ともにDocker HubでDockerイメージが公開されており、以下のようにDockerで実行することが可能です。
Docker Registry v1
$ docker run -d -p 5000:5000 registry:latest
Docker Registry v2
$ docker run -d -p 5000:5000 registry:2.0
いずれもそのままでは既定のコンフィグで動作するため、別途Dockerfileを用意してカスタムイメージを作成するか、-eオプションで環境変数を用いて設定を変更し利用します。v1/v2で環境変数の互換性はないので、v1はこちら、v2はこちらを参考にしましょう。
バックエンドの選択
Docker RegistryはDockerイメージのデータ格納領域として様々なストレージサービスをサポートします。AWS環境であれば、信頼性や保存コストの点でAmazon S3一択で問題ないでしょう。EC2インスタンスで実行するのであれば、Docker Registryを実行するインスタンスにIAMロールをあらかじめ設定しておくとAWSのAPIキーを省略して利用でき、よりセキュアにできます *1。
Docker Registry v2でS3バックエンドの実行例
$ docker run -d -p 5000:5000 \ -e REGISTRY_STORAGE s3 \ -e REGISTRY_STORAGE_S3_REGION <リージョン名> \ -e REGISTRY_STORAGE_S3_BUCKET <バケット名> \ -e REGISTRY_STORAGE_S3_ROOTDIRECTORY / \ registry:2.0
TLS(HTTPS)サポートを付けるか
DockerホストとRegistry間の通信は、ポート番号ではなくRegistryの設定でHTTPとHTTPSを選択 *2し、HTTPSの場合はSSL証明書が必要です。一方HTTPの場合はDockerホスト側でチェックが入り、特定ホスト以外は"非セキュア"として通信が許可されません。インターネットを介する場合はHTTPSが望ましいですが、VPC(AWS内のプライベートネットワーク)に閉じる通信であれば、HTTPで問題無いと判断する場合もあるでしょう。HTTPで通信するための方法を2つ紹介します。
ローカル接続
Dockerホスト側のチェックでは、既定でループバックアドレス(127.0.0.0/8)とのHTTPが許可されます。そこで、 Dockerホスト全台のローカルでDocker Registryを実行する構成が考えられます。Docker Registry自体はステートレスなWeb APIサーバーですので、共通のストレージバックエンドを参照するようにしておけばDockerイメージの共有に問題はありません *3。
Beanstalk環境であれば、.ebextensionsという設定でDockerイメージのpullの前後でコマンドを実行する仕組みがあるため、そこでDocker Registryコンテナの実行/終了をキックする非常駐な構成が可能です。ちょっと古いですが、AWS SAブログの@thekentiestさんのブログ記事に手順と設定例があります。v1のみの紹介ですが、v2でも動作することを確認しました。
ECS環境の場合は、全台でRegistryを実行するためにServiceスケジューラを利用するのが良いでしょう。ECSインスタンスがAuto Scalingであれば、こちらのエントリーのように連動する設定にしておくと管理が楽だと思います。
いずれの場合でも、docker push
する開発機のローカルにもDocker Registryが必要なことに注意しましょう。
--insecure-registryオプション
Dockerホスト側のチェックで、Registryとの非セキュアな通信を許可するオプションとして--insecure-registryオプションがあります。Docker RegistryでHTTP通信を設定する場合と、後述の自己署名証明書の追加をせずにHTTPS通信を行う場合に指定します。DNS名/ドメイン名とIPアドレスのCIDR表記がサポートされます。
- myregistry.local:5000
- 10.0.0.0/16:5000
Docker Registryとの通信はDockerデーモンが行うため、--insecure-registryオプションはDockerデーモンの起動オプションに付与し、既にDockerデーモンが実行中の場合はデーモンの再起動が必要です。Amazon LinuxなどRedHat系ディストリビューションの場合は、/etc/sysconfig/docker(ファイル名(≒サービス名)はディストリビューションによって異なる)ファイルに以下のように記述します。
# Additional startup options for the Docker daemon, for example: # OPTIONS="--ip-forward=true --iptables=true" OPTIONS="--insecure-registry 10.0.0.0/16:5000"
Beanstalk環境では、.ebextensionsの設定ではDockerデーモンが先に起動してしまうため対応できません。カスタムAMIを作成する方法が考えられますが、インスタンスのメンテナンスが煩雑になる点に注意しましょう。
ECS環境では、ECSクラスタに参加するためインスタンスの起動時にamazon/amazon-ecs-agentコンテナが実行されるので、その後でdockerサービスのみを再起動することが難しい場合があります。インスタンスの再起動も検討しましょう。
自己署名証明書によるHTTPS構成
HTTPS通信にする場合は、ValidなSSL証明書を用意するのがベストですがRegistryのために購入するのも大げさですので、自己署名証明書で済ませたいところですよね。自己署名証明書を利用するためには、証明書をDockerホストに配置した上で、Docker RegistryのHTTPS通信を構成します。
自己署名証明書の作成
一般的な作成方法で構いません。今回はDockerドキュメントの手順に沿って作成してみます。
$ mkdir certs $ openssl req \ > -newkey rsa:2048 -nodes -keyout certs/domain.key \ > -x509 -days 365 -out certs/domain.crt Generating a 2048 bit RSA private key ........................+++ .............................+++ writing new private key to 'certs/domain.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [XX]:JP State or Province Name (full name) []:Tokyo Locality Name (eg, city) [Default City]:Chiyoda-ku Organization Name (eg, company) [Default Company Ltd]:Classmethod Organizational Unit Name (eg, section) []:AWS Consulting Common Name (eg, your name or your server's hostname) []:ip-172-31-7-161 Email Address []:admin@ip-172-31-7-161 $ ls certs $ ls certs/ domain.crt domain.key
DockerホストへのCA証明書の追加
作成した証明書を各Dockerホストの/etc/docker/certs.d/<Registryホスト名>:<ポート番号>/ca.crtファイルとしてコピーします。(今回は同じホストで検証しましたが、実際はリモートコピーなどを利用します)
$ sudo mkdir -p /etc/docker/certs.d/ip-172-31-7-161:5000/ $ sudo cp certs/domain.crt /etc/docker/certs.d/ip-172-31-7-161:5000/ca.crt
なお、この証明書を設定するとDockerデーモンが元々あるルート証明書を見に行かなくなるようで、以下の構成だとS3とのHTTPS通信時の証明書検証に失敗します。
- 同一ホストでRegsitryを実行
- RegistryのバックエンドがAmazon S3
ひとまず以下のようにルート証明書のシンボリックリンクを張ってエラーは回避できましたが、正しい対処なのか自信がないので、真っ当な対処方法があれば教えてください!
$ ln -s /etc/pki/tls/certs/ca-bundle.crt /etc/docker/certs.d/ip-172-31-7-161:5000/ca-bundle.crt
Docker Registry v2でHTTPS構成の実行例
Registry側でHTTPSを構成します。v1の場合はRegistry自体ではHTTPSをサポートしないようなので、NginxやAmazon ELBなどのリバースプロキシでHTTPSを構成しましょう。v2は組み込みでHTTPSをサポートするので、設定に追加してリバースプロキシなしで利用できます。HTTPS通信にはそれなりに負荷がかかるので、v2でも必要に応じてリバースプロキシによるSSLオフロードを検討しましょう。
$ docker run -d -p 5000:5000 \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ -v $(pwd)/certs:/certs \ registry:2.0
Multi-AZ構成
Docker RegistryはシンプルなWeb APIサーバーですので、ELBをフロントにし複数のインスタンスで実行するDocker Registryにトラフィックを転送する構成が可能です。インスタンスを複数のAvailability Zoneに配置すればデータセンターレベルの障害を想定したMulti-AZ構成とすることもできます。ローカル接続での全台実行でない構成であれば検討をお奨めします。
まとめ
Docker Registryの構成パターンについて、いろいろご紹介しました。このほかにもBASIC認証やRedisによるキャッシュ機能もあったりするのですが、また別のブログ記事でまとめたいと思います。Docker RegistryでプライベートなDockerイメージ管理を活用しましょう!